package com.helloscala.model

import scala.collection.mutable

import org.squeryl.{Session, KeyedEntity}
import org.squeryl.dsl.CompositeKey2
import net.liftweb.common.{Empty, Full, Box}

import yangbajing.util.Pagination

import com.helloscala.common.{Tag, TagCode}

import MyTypeMode._

object MTag {
  def findAllPopular(limit: Int): List[Tag] =
    findAll(0, limit)

  def findById(tag: String): Box[Tag] =
    transaction {
      val sql = "select tag, count(tag) tag_count from tag_ where tag = ? group by tag"
      val conn = Session.currentSession.connection
      val pstmt = conn.prepareStatement(sql)
      pstmt.setString(1, tag)
      val rs = pstmt.executeQuery()
      if (rs.next()) Full(Tag(rs.getString(1), rs.getLong(2)))
      else Empty
    }

  def findAllDocumentIds(tag: String): List[String] =
    transaction(from(Entities.tags)(at =>
      where(
        at.tag === tag
      ) select at.ref_id).toList)

  def size(author: Option[String] = None, documentId: Option[String] = None): Long =
    transaction(from(Entities.documents, Entities.tags)((a, at) =>
      where(
        (a.author === author.?) and
          (a.id === documentId.?) and
          (a.id === at.ref_id)
      ) compute countDistinct(at.tag))
    )

  def pagination(_curPage: Int, _limit: Int, author: Option[String]): Pagination[Tag] =
    new Pagination[Tag] {
      val curPage: Int = _curPage
      val limit = _limit
      val total = size(author = author)
      val page: List[Tag] = findAll(offset, limit, author = author)
    }

  def findAll(offset: Int, limit: Int, author: Option[String] = None): List[Tag] = {
    val buffer = mutable.ListBuffer[Tag]()

    val _sql = """select at.tag, count(at.ref_id) tag_count
                 | from tag_ at, document_ a
                 | where %s at.ref_id = a.id
                 | group by at.tag
                 | order by tag_count desc, tag asc
                 | offset ? limit ?""".stripMargin

    val sql = author match {
      case Some(v) => _sql format s"a.author = ? and "
      case None => _sql format ""
    }

    var idx = 1

    transaction {
      val conn = Session.currentSession.connection
      val pstmt = conn.prepareStatement(sql)
      author foreach {
        v => pstmt.setString(1, v)
          idx += 1
      }
      pstmt.setInt(idx, offset)
      idx += 1
      pstmt.setInt(idx, limit)
      val rs = pstmt.executeQuery()
      while (rs.next())
        buffer += Tag(rs.getString("tag"), rs.getLong("tag_count"))
    }

    buffer.toList
  }
}

case class MTag(ref_id: String, tag: String, code: TagCode.Value = TagCode.Document) extends KeyedEntity[CompositeKey2[String, String]] {
  def this() {
    this("", "")
  }

  def id = compositeKey(ref_id, tag)
}
